package logger2;

import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import zerdlib.events.containers.ListenableSelfKeyTreeMap;
import zerdlib.events.containers.ListenableSet;
import zerdlib.namedObject.NamedObject;

import logger2.filter.NameObjectKeyGetter;
import logger2.printer.Printer;

public class Logger implements NamedObject {
	private static List<LogRecord> logs = Collections.synchronizedList(new LinkedList<LogRecord>());
	private static Set<Printer> printers = new HashSet<>();
	
	private static ListenableSet<String> threadNames = new ListenableSelfKeyTreeMap<String, String>(new NameObjectKeyGetter());
	private static ListenableSet<String> classNames = new ListenableSelfKeyTreeMap<String, String>(new NameObjectKeyGetter());
	private static ListenableSelfKeyTreeMap<String, Logger> loggers = new ListenableSelfKeyTreeMap<String, Logger>(new NameObjectKeyGetter());
	
	private String name;
	
	private Logger(String name) {
		super();
		this.name = name;
	}
	
	public static Logger getLogger(String name) {
		if(!loggers.contains(name)) {
			loggers.add(new Logger(name));
		}
		return loggers.get(name);
	}
	
	public static boolean addPrinter(Printer printer) {
		return printers.add(printer);
	}

	public static boolean removePrinter(Printer printer) {
		return printers.remove(printer);
	}
	
	public static ListenableSet<String> getThreadNames() {
		return threadNames;
	}
	
	public static ListenableSet<Logger> getLoggerNames() {
		return loggers;
	}
	
	public static ListenableSet<String> getClassNames() {
		return classNames;
	}

	private void internal_log(String message, Level lvl) {
		LogRecord record = new LogRecord(name, message, lvl);
		logs.add(record);
		threadNames.add(record.getThreadName());
		classNames.add(record.getStackTraceElement().getClassName());
		for(Printer p : printers) {
			p.notify(record);
		}
	}
	public void log(String message, Level lvl) {
		internal_log(message, lvl);
	}
	public void finest(String message) {
		internal_log(message, Level.FINEST);
	}
	public void finer(String message) {
		internal_log(message, Level.FINER);
	}
	public void fine(String message) {
		internal_log(message, Level.FINE);
	}
	public void config(String message) {
		internal_log(message, Level.CONFIG);
	}
	public void info(String message) {
		internal_log(message, Level.INFO);
	}
	public void warning(String message) {
		internal_log(message, Level.WARNING);
	}
	public void severe(String message) {
		internal_log(message, Level.SEVERE);
	}

	public static void assertion(boolean b, String message) {
		if(!b)
			getLogger("assert").internal_log(message, Level.SEVERE);
	}

	@Override
	public String getName() {
		return name;
	}
	
}
